package lib;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.file.FileConnection;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import view.Mingle;

import lib.classes.Profile;
import model.DB;
import net.rim.blackberry.api.browser.URLEncodedPostData;
import net.rim.blackberry.api.messagelist.ApplicationIcon;
import net.rim.blackberry.api.messagelist.ApplicationMessage;
import net.rim.blackberry.api.messagelist.ApplicationMessageFolderRegistry;
import net.rim.device.api.io.IOUtilities;
import net.rim.device.api.math.Fixed32;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.ui.UiApplication;

public class Util 
{
	
	private Util(){}	
	public static boolean isRegistered = false;
	public static final String APPDIR_SD = "file:///SDCard/mingleVD/";
	public static final String APPDIR_D = "file:///store/home/user/mingleVD/";
	public static final String regFile = "registration.vd";
	public static String APPPATH = APPDIR_D;
	
    public static String Host(String url, int type)
    {
    	UrlFactory servicemaster ;
    	String iniRequestUrl = url;//"http://78.40.39.146:7154";
   
		switch(type)
		{
			case UrlFactory.TRANSPORT_WIFI:
				servicemaster = new UrlFactory(new int[] {UrlFactory.TRANSPORT_WIFI,});
				break;
			case UrlFactory.TRANSPORT_DIRECT_TCP:
				servicemaster = new UrlFactory(new int[] {UrlFactory.TRANSPORT_DIRECT_TCP,});
				break;
			case UrlFactory.TRANSPORT_WAP2:
				servicemaster = new UrlFactory(new int[] {UrlFactory.TRANSPORT_WAP2,});
				break;
			case UrlFactory.TRANSPORT_BES:
				servicemaster = new UrlFactory(new int[] {UrlFactory.TRANSPORT_BES,});
				break;
			case UrlFactory.TRANSPORT_BIS:
				servicemaster = new UrlFactory(new int[] {UrlFactory.TRANSPORT_BIS,});
				break;
			default:
				servicemaster = new UrlFactory(UrlFactory.DEFAULT_TRANSPORT_ORDER);
				break;
		}	
    		//servicemaster = new UrlFactory(new int[] {UrlFactory.TRANSPORT_WIFI, UrlFactory.TRANSPORT_DIRECT_TCP, UrlFactory.TRANSPORT_WAP2,});
        	
        iniRequestUrl = servicemaster.appendRimConnectionParam(iniRequestUrl, "");//";ConnectionTimeout=60000");
        	
    	
    	if(DeviceInfo.isSimulator()) 
    	{
    		   iniRequestUrl = url+";deviceside=true";
    	}
    	
    	return iniRequestUrl;
    	//return "http://gruuvz.com/audio/09-Track-9.mp3";
    }
	
	
	
	public static EncodedImage resizeImage(EncodedImage image, int newWidth, int newHeight) 
	{
	    int scaleFactorX = Fixed32.div(Fixed32.toFP(image.getWidth()), Fixed32.toFP(newWidth));
	    int scaleFactorY = Fixed32.div(Fixed32.toFP(image.getHeight()), Fixed32.toFP(newHeight));
	    return image.scaleImage32(scaleFactorX, scaleFactorY);
	} 
	/**
	 * Output the debug message directly to the standard out. Along with the
	 * message, the name of the current thread is also printed.
	 * <p>
	 * Logging facilities can be added at convenience to provide exclusive
	 * logging information that's relevant to RadioStation.ForMe.
	 */
	public static void debug(String message) {
		System.out.println("rsfm("+Thread.currentThread().getName() + "): " + message);
	}
	
	
	public static void getWebData(final String url, final WebDataCallback callback) throws IOException
	{
		Thread t = new Thread(new Runnable()
		{
			public void run()
			{
				HttpConnection connection = null;
				InputStream inputStream = null;

				try
				{
					connection = (HttpConnection) Connector.open(url, Connector.READ, true);
					inputStream = connection.openInputStream();
					byte[] responseData = new byte[10000];
					int length = 0;
					StringBuffer rawResponse = new StringBuffer();
					while (-1 != (length = inputStream.read(responseData)))
					{
						rawResponse.append(new String(responseData, 0, length));
					}
					int responseCode = connection.getResponseCode();
					if (responseCode != HttpConnection.HTTP_OK)
					{
						throw new IOException("HTTP response code: "
								+ responseCode);
					}

					final String result = rawResponse.toString();
					UiApplication.getUiApplication().invokeLater(new Runnable()
					{
						public void run()
						{
							callback.callback(result);
						}
					});
				}
				catch (final Exception ex)
				{
					UiApplication.getUiApplication().invokeLater(new Runnable()
					{
						public void run()
						{
							callback.callback("Exception (" + ex.getClass() + "): " + ex.getMessage());
						}
					});
				}
				finally
				{
					try
					{
						inputStream.close();
						inputStream = null;
						connection.close();
						connection = null;
					}
					catch(Exception e){}
				}
			}
		});
		t.start();
	}
	public static void writeToFile(String text, String file)
	{
		FileConnection fc;
		try 
		{
			fc = (FileConnection)
			Connector.open(file,Connector.READ_WRITE);
		
			if(!fc.exists()) fc.create();
			OutputStream os =fc.openOutputStream();
			os.write(text.getBytes());
			os.close(); 
			fc.close();
		} catch (IOException e) {
			log("Error- WritetooFile:: " + e.getMessage());
		}
	}
	public static String readTextFile(String fName) {
		  String result = null;
		  FileConnection fconn = null;
		  DataInputStream is = null;
		  try 
		  {
		   fconn = (FileConnection) Connector.open(fName, Connector.READ_WRITE);
		   is = fconn.openDataInputStream();
		   byte[] data = IOUtilities.streamToBytes(is);
		   result = new String(data);
		  } catch (IOException e) {
		   System.out.println("ERROR:: READ file - "+e.getMessage());
		  } finally {
		   try {
		    if (null != is)

		     is.close();
		    if (null != fconn)
		     fconn.close();
		   } catch (IOException e) {
		    System.out.println("ERROR:: READ fileIO - "+e.getMessage());
		   }
		  }
		  return result;
	}
	
	public static boolean createDirectory(final String newDirectory) {
        // First step make sure temp directory is there
        FileConnection fconn = null;
        boolean returnFlag = false;
        try {
            log("File connection open: " + newDirectory);
            fconn = (FileConnection) Connector.open(newDirectory, Connector.READ_WRITE);
            if ( !fconn.exists() ) {
                fconn.mkdir();  // create the folder/file if it doesn't exist
            }
            fconn.close();
            fconn = null;
            returnFlag = true;
        } catch (Exception e) {
            String errorMessage = "Error creating directory: " + newDirectory + '\n' + e.toString();
            log(errorMessage);
            returnFlag = false;
        } finally {
            try {
                if ( fconn != null ) {
                    fconn.close();
                    fconn = null;
                }
            } catch (Exception e) {
            }
        }
        return returnFlag;
    }
	
	public static void log(String x)
	{
		System.out.println(x);
	}
	
	public static void showNotifyIcon()
	{
		ApplicationMessageFolderRegistry reg =  ApplicationMessageFolderRegistry.getInstance();
		ApplicationIcon newIcon = 
			   new ApplicationIcon( EncodedImage.getEncodedImageResource( "ml_sample_new.png" ) );
			ApplicationIcon openedIcon = 
			   new ApplicationIcon( EncodedImage.getEncodedImageResource( "ml_sample_opened.png" ) );
		int MESSAGE_TYPE = 0;
		int STATUS_NEW = ApplicationMessage.Status.UNOPENED;
		int STATUS_OPENED = ApplicationMessage.Status.OPENED;

		reg.registerMessageIcon( MESSAGE_TYPE, STATUS_NEW, newIcon );
		reg.registerMessageIcon( MESSAGE_TYPE, STATUS_OPENED, openedIcon );
	}
	
	public static int getAge(Date dateOfBirth) {

	    Calendar today = Calendar.getInstance();
	    Calendar birthDate = Calendar.getInstance();

	    int age = 0;

	    birthDate.setTime(dateOfBirth);
	    if (birthDate.after(today)) {
	        throw new IllegalArgumentException("Can't be born in the future");
	    }

	    age = today.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR);

	    // If birth date is greater than todays date (after 2 days adjustment of leap year) then decrement age one year   
	    if ( (birthDate.get(Calendar.YEAR) - today.get(Calendar.YEAR) > 3) ||
	            (birthDate.get(Calendar.MONTH) > today.get(Calendar.MONTH ))){
	        age--;

	     // If birth date and todays date are of same month and birth day of month is greater than todays day of month then decrement age
	    }else if ((birthDate.get(Calendar.MONTH) == today.get(Calendar.MONTH )) &&
	              (birthDate.get(Calendar.DAY_OF_MONTH) > today.get(Calendar.DAY_OF_MONTH ))){
	        age--;
	    }

	    return age;
	}
	
	public static EncodedImage scaleImageToWidth(EncodedImage encoded, int newWidth) {
		return scaleToFactor(encoded, encoded.getWidth(), newWidth);
	}
	
	public static EncodedImage scaleImageToHeight(EncodedImage encoded, int newHeight) {
		return scaleToFactor(encoded, encoded.getHeight(), newHeight);
	}
	
	public static EncodedImage scaleToFactor(EncodedImage encoded, int curSize, int newSize) {
		int numerator = Fixed32.toFP(curSize);
		int denominator = Fixed32.toFP(newSize);
		int scale = Fixed32.div(numerator, denominator);

		return encoded.scaleImage32(scale, scale);
	}
	
	/**
     * Displays a node at a specified depth, as well as all its descendants.
     * 
     * @param node The node to display.
     * @param depth The depth of this node in the document tree.
     */
	
	public static  void displayNode( Node node, Vector bag, Vector p ) 
    {        
        // Because we can inspect the XML file, we know that it contains only XML elements
        // and text, so this algorithm is written specifically to handle these cases.  
        // A real-world application will be more robust, and will handle all node types. 
        // See the entire list in org.w3c.dom.Node.      
        // The XML file is laid out such that each Element node will either have one Text 
        // node child (e.g. <Element>Text</Element>), or >= 1 children consisting of at 
        // least one Element node, and possibly some Text nodes.  Start by figuring out
        // what kind of node we're dealing with.
        if ( node.getNodeType() == Node.ELEMENT_NODE ) 
        {
            StringBuffer buffer = new StringBuffer();
            
            NodeList childNodes = node.getChildNodes();
            int numChildren = childNodes.getLength();
            Node firstChild = childNodes.item( 0 );
            
            // If the node has only one child and that child is a Text node, then it's of 
            // the form  <Element>Text</Element>, so print 'Element = "Text"'.
            if ( numChildren == 1 && firstChild.getNodeType() == Node.TEXT_NODE ) 
            {
               buffer.append(firstChild.getNodeValue());
                bag.addElement(buffer.toString());
            } 
            else 
            {
                // The node either has > 1 children, or it has at least one Element node child. 
                // Either way, its children have to be visited.  Print the name of the element
                // and recurse.
                //buffer.append( node.getNodeName() );
                //add( new RichTextField( buffer.toString() ) );
                
                // Recursively visit all this node's children.

            	Vector v = new Vector();
                for ( int i = 0; i < numChildren; ++i ) 
                {
                    displayNode( childNodes.item( i ), v ,p);
                     
                }
                p.addElement(v);
            }
        } 
        else 
        {
            // Node is not an Element node, so we know it is a Text node.  Make sure it is 
            // not an "empty" Text node (normalize() doesn't consider a Text node consisting
            // of only newlines and spaces to be "empty").  If it is not empty, print it.
            String nodeValue = node.getNodeValue();
            if ( nodeValue.trim().length() != 0 ) 
            {
            	StringBuffer buffer = new StringBuffer();
                buffer.append( '"' ).append( nodeValue ).append( '"' );
                System.out.println(buffer.toString());
            }
        }
    }
	

	public static Profile updateDBFromServer(DB db)
	{
		Profile p = null;
		try
        {
			HttpConnection httpConn = (HttpConnection)Connector.open(Util.Host(DB.serverURL, -1), Connector.READ_WRITE);
			URLEncodedPostData encPostData = new URLEncodedPostData("UTF-8", false);
        	encPostData.append("action", "findprofile");
        	encPostData.append("pin", DeviceInfo.getDeviceId()+"");
        	byte[] postDataBytes = encPostData.getBytes();
        	
        	httpConn.setRequestMethod(HttpConnection.POST);
        	httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        	httpConn.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
        	httpConn.setRequestProperty("Content-Language", "en-US");
        	httpConn.setRequestProperty("Content-Length",new Integer(postDataBytes.length).toString());
        	
            int rc = httpConn.getResponseCode();
            if(rc == HttpConnection.HTTP_OK) 
            {
            	OutputStream os = httpConn.openOutputStream();
                os.write( postDataBytes );
                InputStream is;
                is = httpConn.openInputStream();
                //is.read( _data );
                p = Mingle.returnProfileFromXML(is);
                if(p != null)
                {
                	db.insertProfileIntoDB(p);
                }
                
            } 
        }catch(Exception e)
        {
        	
        }
        return p;
	}
	

	public static boolean emailExists(String email) {
		
		try
        {
			HttpConnection httpConn = (HttpConnection)Connector.open(Util.Host(DB.serverURL, -1), Connector.READ_WRITE);
			URLEncodedPostData encPostData = new URLEncodedPostData("UTF-8", false);
        	encPostData.append("action", StringResource.EMAILEXISTS);
        	encPostData.append("pin", DeviceInfo.getDeviceId()+"");
        	encPostData.append("email", email);
        	byte[] postDataBytes = encPostData.getBytes();
        	
        	httpConn.setRequestMethod(HttpConnection.POST);
        	httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        	httpConn.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
        	httpConn.setRequestProperty("Content-Language", "en-US");
        	httpConn.setRequestProperty("Content-Length",new Integer(postDataBytes.length).toString());
        	
            int rc = httpConn.getResponseCode();
            if(rc == HttpConnection.HTTP_OK) 
            {
            	OutputStream os = httpConn.openOutputStream();
                os.write( postDataBytes );
                InputStream is;
                is = httpConn.openInputStream();
                byte[] _data = new byte[100];
                is.read( _data );
                String x = new String(_data);
                System.out.println(">>Debug: "+x);
                return x.toLowerCase().indexOf("true") >= 0;
            }else
            {
            	System.out.println("RC is not ok: " + rc);
            }
        }catch(Exception e)
        {
        	System.out.println(e.getMessage());
        }
		return false;
	}
	
	public static boolean isNumeric(String value)
	{
		try  
	    {  
	      double d = Double.parseDouble(value);  
	    }  
	    catch(NumberFormatException nfe)  
	    {  
	      return false;  
	    }  
	    return true;  
	}



	public static boolean migratePinToEmail(int deviceId, String text) 
	{
		//TODO
		
		return false;
	}
}
